home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 7661 / 7661.xpi / components / RILassetManager.js < prev    next >
Encoding:
Text File  |  2009-12-11  |  11.7 KB  |  324 lines

  1. /*
  2.  
  3. License: This source code may not be used in other applications whether they
  4. be personal, commercial, free, or paid without written permission from Read It Later.
  5.  
  6.  
  7. /////////
  8. DEVELOPER API: readitlaterlist.com/api/
  9. /////////
  10.  
  11. If you would like to customize Read It Later or build an application that works with
  12. Read it Later take a look at the READ IT LATER OPEN API:
  13. http://readitlaterlist.com/api/
  14.  
  15. Suggestions for additions to Read It Later are VERY welcome.  A large number of user
  16. suggestions have been implemented.  Please let me know of any additional features you
  17. are seeking at: http://readitlaterlist.com/support/
  18.  
  19. Thanks
  20.  
  21. */
  22.  
  23. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  24.  
  25.  
  26. function RILassetManager() {
  27.     // Set and create download directories
  28.     this.DEFAULT_FOLDER_NAME    = 'ReadItLater';
  29.     this.PAGES_FOLDER_NAME    = 'RIL_pages'; // !!!!! changes here should be checked against RIL.getItemForCurrentPage
  30.     this.ASSETS_FOLDER_NAME    = 'RIL_assets'; // !!!!! changes here should be checked against RIL.getItemForCurrentPage
  31.     
  32. }
  33.  
  34. RILassetManager.prototype = {
  35.  
  36.   // properties required for XPCOM registration:
  37.   classDescription: "Read It Later Asset Manager Javascript XPCOM Component",
  38.   classID:          Components.ID("{b9b44920-aabb-11de-8a39-0800200c9a66}"),
  39.   contractID:       "@ril.ideashower.com/rilassetmanager;1",
  40.  
  41.   QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIRILassetManager]),
  42.  
  43.   //////////////////////////////////////////////////
  44.       
  45.     init : function()
  46.     {
  47.         // IO service not allowed because it is not threadsafe!
  48.         this.FILE           = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
  49.         this.PREFS          = Components.classes['@ril.ideashower.com/rilprefs;1'].getService().wrappedJSObject;
  50.         this.JSON           = Components.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON);
  51.         
  52.     this.PATH_PROF         = this.FILE.get("ProfD", Components.interfaces.nsIFile).path;
  53.     this.FD             = this.PATH_PROF.match(/([\/\\])/)[0];
  54.     
  55.         this.PATH_RIL       = this.PREFS.get('offlinePath');
  56.         this.PATH_RIL       = this.PATH_RIL ? this.PATH_RIL : (this.PATH_PROF + this.FD + this.DEFAULT_FOLDER_NAME);
  57.                 
  58.         this.PATH_PAGES     = this.PATH_RIL + this.FD + this.PAGES_FOLDER_NAME;        
  59.         this.PATH_ASSETS    = this.PATH_RIL + this.FD + this.ASSETS_FOLDER_NAME;
  60.         
  61.         this.DIR_RIL        = this.dir(this.PATH_RIL, true);        
  62.         this.DIR_PAGES      = this.dir(this.PATH_PAGES, true);
  63.         this.DIR_ASSETS     = this.dir(this.PATH_ASSETS, true);
  64.     },
  65.       
  66.     file : function(path) {    
  67.     let file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
  68.         file.initWithPath(path);
  69.     return file;
  70.     },
  71.     
  72.     dir : function(path, createIfDoesntExist)
  73.     {
  74.         let file = this.file(path);
  75.         
  76.         if (createIfDoesntExist)
  77.         {
  78.             if (!file.exists() || !file.isDirectory()) file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0777);
  79.         }
  80.         
  81.         return file;
  82.     },
  83.     
  84.     typeCastTrueFalseNull : function(string)
  85.     {
  86.     return string == 'true' ? true : string == 'false' ? false : string == 'null' || string == 'undefined' ? null : string;
  87.     },
  88.  
  89.     pathsForLiteral : function( literal, baseURL, relative, forceType )
  90.     {
  91.     // because args come through as strings, need to do some type casting
  92.     baseURL = this.typeCastTrueFalseNull(baseURL);
  93.     relative = this.typeCastTrueFalseNull(relative);
  94.     forceType = this.typeCastTrueFalseNull(forceType);    
  95.     
  96.         try {
  97.         // Find absolute path
  98.         let absoluteURI = this.parseUri( literal, baseURL );        
  99.         let absolute = absoluteURI.spec;
  100.         
  101.         if (absoluteURI.scheme != 'http' && absoluteURI.scheme != 'https') return; // no other schemes allowed
  102.         
  103.         // Decode the url (just & right now)
  104.         absolute = absolute.replace('&', '&');
  105.         
  106.         
  107.         // Fix up the absolute path to use when saving to path
  108.         // query string data should be moved to file name
  109.         // Stylesheets should be forced to end in css
  110.         // ex: img.jpg?test=1 => imgtest%31.jpg
  111.         // ex: index.php?blah=1 => indexblah%31.css
  112.         
  113.         // Fix lastPathComponent as described above
  114.         let pathParts = absoluteURI.path.split('/');
  115.         let last = pathParts[ pathParts.length-1 ];
  116.         
  117.         // Move query string info into filename
  118.         if (last)
  119.         {
  120.         let extension   = absoluteURI.file.replace(/[^\.]*\.(.*)$/, '.$1');        
  121.         let newPath     = last.replace(extension, '');
  122.         newPath         +=  absoluteURI.query ? encodeURIComponent(absoluteURI.query) : '';
  123.         newPath         +=  forceType ? (forceType==2 ? '.css' : '') : extension;
  124.         
  125.         pathParts[ pathParts.length-1 ] = newPath;
  126.         }
  127.         
  128.         let absolutePath = this.cleanPathName( pathParts.join(this.FD) );
  129.         
  130.         // Break up path parts to figure out folders
  131.         pathParts = absolutePath.split(this.FD);
  132.         
  133.         // Build Path
  134.         let assetDomain = absoluteURI.host;
  135.         let path = this.PATH_ASSETS + this.FD + assetDomain;
  136.         for(let i in pathParts) {
  137.         if (!pathParts[i]) continue;
  138.         if (pathParts[i].length > 50)
  139.             pathParts[i] = pathParts[i].substr(0, 50); // make sure no folder will be over file name limits
  140.         path += this.FD + pathParts[i];
  141.         
  142.         }
  143.         
  144.         
  145.         // -- Moved file exists check out and only used when it needs it -- //
  146.         
  147.         
  148.         // Make relative Path
  149.         // Remove front end of path (offline directory path)
  150.         // second replace strips prefix slash if it exists so we don't get ../..//something
  151.         // relative path should only have forward slashes: file://something/something
  152.         let relativePath = path.replace( this.PATH_RIL , '' ).replace(new RegExp('^\\'+this.FD), '').replace(/\\/gi, '/');
  153.         
  154.         // If the path needs to be relative (for example its linked from inside a stylesheet, add the required number of ../
  155.         if (relative) {
  156.         let baseItemInfoJSON = this.pathsForLiteral( baseURL, baseURL, false, false );
  157.         if (baseItemInfoJSON)
  158.         {
  159.             let baseItemInfo = this.JSON.decode(baseItemInfoJSON);
  160.             let baseItemPathParts = baseItemInfo.assetRelativePath.split('/');
  161.             
  162.             let relativePrefix = '';
  163.             let parts = baseItemPathParts.length - 3; //2 for the ../ added below, and 1 for moving out of current
  164.             for(let i=0; i<parts; i++)
  165.             {
  166.             relativePrefix += '../';
  167.             }
  168.             relativePath = relativePrefix + relativePath;
  169.         }
  170.         // TODO - what to do for else?
  171.         
  172.         } else {
  173.         
  174.         // Needs to go out of RIL_pages and into RIL_assets, first ../ gets it out of items folder, second ../ gets it out of RIL_pages
  175.         relativePath = '../../' + relativePath;
  176.         
  177.         }
  178.         
  179.         return this.JSON.encode({
  180.         literal:            literal,
  181.         absolute:           absolute,
  182.         assetPath:          path,
  183.         assetRelativePath:  relativePath,
  184.         assetDomain:        assetDomain,
  185.         assetExists:         this.assetExists(path)
  186.         });
  187.     
  188.     } catch(e) {
  189.         Components.utils.reportError('Error caused by '+ literal + "\n" + baseURL);
  190.         Components.utils.reportError(e);
  191.     }
  192.     },
  193.     cleanPathName : function(path)
  194.     {        
  195.         path = path.replace( this.FD=='/' ? /\\/gi : /\//gi, '' ); // opp slash as defined in FD
  196.         return path.replace(/[\=\?\&\%\;\:\*\"\<\>\|]/gi, '');
  197.     },
  198.     
  199.     assetExists : function(assetPath)
  200.     {
  201.     let file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
  202.         file.initWithPath(assetPath);        
  203.         return file.exists();
  204.     },
  205.     
  206.     // -- //
  207.     
  208.     folderPathForItemId : function(itemId, urlFormat) {
  209.     let path = this.PATH_PAGES + this.FD + itemId + this.FD;
  210.     if (urlFormat)
  211.         return 'file:///' + path.replace(/\\/g,'/');
  212.     else
  213.         return path;
  214.     },
  215.     
  216.     folderForItemId : function(itemId) {
  217.     return this.file(this.folderPathForItemId(itemId));
  218.     },
  219.     
  220.     removeFolderForItemId : function(itemId) {    // TODO is the folder.exists check ness?  Is that a point of slowdown?
  221.     let folder = this.folderForItemId( itemId );
  222.     if (folder.exists()) folder.remove(true);
  223.     },
  224.     
  225.     // -- //
  226.     
  227.     removeAssetDomain : function(assetDomain) { // TODO is the folder.exists check ness?  Is that a point of slowdown?
  228.     let folder = this.file(this.PATH_ASSETS + this.FD + assetDomain);
  229.     if (folder.exists()) folder.remove(true);
  230.     },    
  231.     
  232.     parseUri : function(urlStr, baseURL)
  233.     {            
  234.         if (urlStr.length > 1250) return; //too long of a url locks browser in parseUri script
  235.         var uri = {};
  236.         
  237.     if (baseURL && !urlStr.match(/^https?:/))
  238.     {
  239.             // if url starts with ./example remove ./
  240.             urlStr = urlStr.replace(/^\.\//, '');
  241.         
  242.         // convert urlStr into a full absolute url
  243.         let parsedBase = this.parseUri(baseURL);
  244.         let baseRoot = parsedBase.protocol + '://' + parsedBase.authority + '/';
  245.         
  246.         if ( urlStr.match(/^\.\.?\//) ) // ../../format.html
  247.         {                
  248.         let relativeBaseParts = parsedBase.relative.split('/');
  249.         if (relativeBaseParts.length < 3)
  250.         {
  251.             urlStr = baseRoot + urlStr.replace(/^(\.\.\/){0,}/,'')
  252.         }
  253.         else
  254.         {
  255.             relativeBaseParts.shift(); //remove first which will be empty  (x)/something/something/
  256.             if (parsedBase.file || relativeBaseParts[relativeBaseParts.length-1].length==0) relativeBaseParts.pop(); //remove end (file)
  257.             
  258.             let end = relativeBaseParts.length - urlStr.match(/\.\.\//g).length;
  259.             let rel = relativeBaseParts.slice(0,end>0?end:0).join('/');
  260.             urlStr = baseRoot + (rel ? rel+'/' : '') + urlStr.replace(/^(\.\.\/){0,}/,'');             
  261.         }
  262.         
  263.         }
  264.         
  265.         else if (urlStr.match(/^\//)) // /format.html
  266.         {
  267.         urlStr = baseRoot.replace(/\/$/,'') + urlStr;
  268.         }
  269.         
  270.         else
  271.         { // format/format.html
  272.         urlStr = baseRoot.replace(/\/$/,'') + parsedBase.directory.replace(/[^\/]*$/,'') + urlStr;
  273.         }
  274.         
  275.     }
  276.     else {
  277.         uri.wasAbsolute = true;        
  278.     }
  279.     
  280.     
  281.         var o = {
  282.             strictMode: false,
  283.             key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
  284.             q:   {
  285.                 name:   "queryKey",
  286.                 parser: /(?:^|&)([^&=]*)=?([^&]*)/g
  287.             },
  288.             parser: {
  289.                 strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
  290.                 loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
  291.             }
  292.         }
  293.         
  294.         var m    = o.parser[o.strictMode ? "strict" : "loose"].exec(urlStr),
  295.             i   = 14;
  296.         
  297.         while (i--) uri[o.key[i]] = m[i] || "";
  298.         
  299.         uri[o.q.name] = {};
  300.         uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
  301.             if ($1) uri[o.q.name][$1] = $2;
  302.         });
  303.         
  304.     uri.spec = urlStr;
  305.     uri.scheme = uri.protocol;
  306.     
  307.         return uri;        
  308.     },
  309.     
  310.     // returns an absolute from a relative or false if it already is an absolute
  311.     getAbsoluteFromRelative : function(urlStr, baseURL)
  312.     {
  313.     let parsed = this.parseUri(urlStr, baseURL);
  314.     return !parsed || !parsed.host || parsed.wasAbsolute ? false : parsed.spec;
  315.     }
  316.     
  317.   
  318. };
  319.  
  320. var components = [RILassetManager];
  321. function NSGetModule(compMgr, fileSpec) {
  322.   return XPCOMUtils.generateModule(components);
  323. }
  324.